package com.beemindz.miyotee.activity;

import java.util.Calendar;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.ToggleButton;

import com.beemindz.miyotee.R;
import com.beemindz.miyotee.provider.MyToDo;
import com.beemindz.miyotee.reminder.ReminderManager;
import com.beemindz.miyotee.utils.CommonUtils;
import com.beemindz.miyotee.utils.Constant;
import com.google.analytics.tracking.android.EasyTracker;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;

public class TaskEditorActivity extends ActionBarActivity {
  // For logging and debugging
  private static final String TAG = "TasksEditorActivity";

  private static final String[] TASK_PROJECTION = new String[] { MyToDo.Tasks._ID, MyToDo.Tasks.COLUMN_NAME_ID,
      MyToDo.Tasks.COLUMN_NAME_USER_NAME, MyToDo.Tasks.COLUMN_NAME_NAME, MyToDo.Tasks.COLUMN_NAME_DESCRIPTION,
      MyToDo.Tasks.COLUMN_NAME_REMINDER_DATE, MyToDo.Tasks.COLUMN_NAME_CREATE_DATE,
      MyToDo.Tasks.COLUMN_NAME_UPDATE_DATE, MyToDo.Tasks.COLUMN_NAME_IS_REMINDER, MyToDo.Tasks.COLUMN_NAME_IS_COMPLETE };

  // This Activity can be started by more than one action. Each action is
  // represented
  // as a "state" constant
  private static final int STATE_EDIT = 0;
  private static final int STATE_INSERT = 1;

  // Global mutable variables
  private int mState;
  private Uri mUri;
  private Cursor mCursor;
  private EditText etName, etDescription;
  private TextView etDate, etTime;
  private RelativeLayout layoutSelectTime, layoutSelectDate;
  private Button btnDelete;
  private CheckBox cbIsComplete;
  private Calendar mCalendar;
  private boolean isReminder;

  /** The view to show the ad. */
  private AdView adView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    Log.d(TAG, "start onCreate:" + Calendar.getInstance().get(Calendar.MILLISECOND));
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_task_editor);

    isReminder = false;

    /*
     * Creates an Intent to use when the Activity object's result is sent back
     * to the caller.
     */
    final Intent intent = getIntent();

    /*
     * Sets up for the edit, based on the action specified for the incoming
     * Intent.
     */

    // Gets the action that triggered the intent filter for this Activity
    final String action = intent.getAction();

    // For an edit action:
    if (Intent.ACTION_EDIT.equals(action)) {

      // Sets the Activity state to EDIT, and gets the URI for the data to
      // be edited.
      mState = STATE_EDIT;
      mUri = intent.getData();

      // For an insert or paste action:
    } else if (Intent.ACTION_INSERT.equals(action)) {

      // Sets the Activity state to INSERT, gets the general note URI, and
      // inserts an
      // empty record in the provider
      mState = STATE_INSERT;
      mUri = getContentResolver().insert(intent.getData(), null);
      /*
       * If the attempt to insert the new note fails, shuts down this Activity.
       * The originating Activity receives back RESULT_CANCELED if it requested
       * a result. Logs that the insert failed.
       */
      if (mUri == null) {

        // Writes the log identifier, a message, and the URI that
        // failed.
        Log.e(TAG, "Failed to insert new task into " + getIntent().getData());

        // Closes the activity.
        finish();
        return;
      }

      // Since the new entry was created, this sets the result to be
      // returned
      // set the result to be returned.
      setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));

      // If the action was other than EDIT or INSERT:
    } else {

      // Logs an error that the action was not understood, finishes the
      // Activity, and
      // returns RESULT_CANCELED to an originating Activity.
      Log.e(TAG, "Unknown action, exiting");
      finish();
      return;
    }

    /*
     * Using the URI passed in with the triggering Intent, gets the note or
     * notes in the provider. Note: This is being done on the UI thread. It will
     * block the thread until the query completes. In a sample app, going
     * against a simple provider based on a local database, the block will be
     * momentary, but in a real app you should use
     * android.content.AsyncQueryHandler or android.os.AsyncTask.
     */
    mCursor = getContentResolver().query(mUri, TASK_PROJECTION, null, null, null);

    // Sets the layout for this Activity. See res/layout/note_editor.xml
    setContentView(R.layout.activity_task_editor);

    // Gets a handle to the EditText in the the layout.
    etName = (EditText) findViewById(R.id.etName);
    etDescription = (EditText) findViewById(R.id.etDescription);
    etDate = (TextView) findViewById(R.id.etDate);
    etTime = (TextView) findViewById(R.id.etTime);
    layoutSelectDate = (RelativeLayout) findViewById(R.id.layoutSelectDate);
    layoutSelectTime = (RelativeLayout) findViewById(R.id.layoutSelectTime);
    btnDelete = (Button) findViewById(R.id.btnDeleteTask);
    mCalendar = Calendar.getInstance();
    cbIsComplete = (CheckBox) findViewById(R.id.cbComplete);

    // set listener delete task.
    btnDelete.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View arg0) {
        confirmDelete().show();
      }
    });

    // custom action bar.
    customActionBar();
    initAdModule(); // admod;

    Log.d(TAG, "end onCreate:" + Calendar.getInstance().get(Calendar.MILLISECOND));
  }

  /**
   * Custom action bar.
   */
  @SuppressLint("InflateParams")
  public void customActionBar() {
    ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayShowCustomEnabled(true);

    actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
    actionBar.setCustomView(R.layout.editor_task_action_bar);

    Button btnCacel = (Button) findViewById(R.id.btnCancel);
    Button btnOk = (Button) findViewById(R.id.btnOK);

    btnCacel.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View arg0) {
        finish();
      }
    });

    btnOk.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View v) {
        addTask();
        finish();
      }
    });
  }

  @Override
  protected void onStart() {
    super.onStart();
    EasyTracker.getInstance(this).activityStart(this);
    Log.i(TAG, "==onStart==");
  }

  @Override
  protected void onStop() {
    super.onStop();
    EasyTracker.getInstance(this).activityStop(this);
    Log.i(TAG, "==onStop==");
  }

  /**
   * This method is called when the Activity is about to come to the foreground.
   * This happens when the Activity comes to the top of the task stack, OR when
   * it is first starting. Moves to the first note in the list, sets an
   * appropriate title for the action chosen by the user, puts the note contents
   * into the TextView, and saves the original text as a backup.
   */
  @Override
  protected void onResume() {
    super.onResume();
    if (adView != null) {
      adView.resume();
    }
    Log.d(TAG, "On Resume");
    /*
     * mCursor is initialized, since onCreate() always precedes onResume for any
     * running process. This tests that it's not null, since it should always
     * contain data.
     */
    if (mCursor != null) {
      // Requery in case something changed while paused (such as the
      // title)
      mCursor = getContentResolver().query(mUri, TASK_PROJECTION, null, null, null);
      mCursor.moveToFirst();

      // Modifies the window title for the Activity according to the
      // current Activity state.
      if (mState == STATE_EDIT) {
        // Set the title of the Activity to include the note title

        int colNameIndex = mCursor.getColumnIndex(MyToDo.Tasks.COLUMN_NAME_NAME);
        int colReminderIndex = mCursor.getColumnIndex(MyToDo.Tasks.COLUMN_NAME_REMINDER_DATE);
        int colIsReminderIndex = mCursor.getColumnIndex(MyToDo.Tasks.COLUMN_NAME_IS_REMINDER);

        String taskName = mCursor.getString(colNameIndex);
        String reminderDate = mCursor.getString(colReminderIndex);

        isReminder = mCursor.getInt(colIsReminderIndex) == 0 ? true : false;

        Log.d(TAG, "reminder date :" + reminderDate);
        mCalendar.setTime(CommonUtils.getDate(reminderDate, Constant.DATE_TIME_FORMAT));
        Log.d(TAG, "Calendar time : " + mCalendar.getTime());
        if (isReminder && mCalendar.getTimeInMillis() <= System.currentTimeMillis()) {
          mCalendar = Calendar.getInstance();
          mCalendar.add(Calendar.MINUTE, Constant.ADDED_MINUTE);
        }

        etName.setTextKeepState(taskName != null ? taskName.trim() : "");
        etName.setSelection(taskName != null ? taskName.trim().length() : 0);
        getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
        isShowReminder();
        ToggleButton tgbSetReminder = (ToggleButton) findViewById(R.id.tgbSetReminder);
        tgbSetReminder.setChecked(isReminder);
        // Sets the title to "create" for inserts
      } else if (mState == STATE_INSERT) {

      }

      /*
       * onResume() may have been called after the Activity lost focus (was
       * paused). The user was either editing or creating a note when the
       * Activity paused. The Activity should re-display the text that had been
       * retrieved previously, but it should not move the cursor. This helps the
       * user to continue editing or entering.
       */

      // Gets the note text from the Cursor and puts it in the TextView,
      // but doesn't change
      // the text cursor's position.
      int colDescriptionIndex = mCursor.getColumnIndex(MyToDo.Tasks.COLUMN_NAME_DESCRIPTION);
      String taskDescription = mCursor.getString(colDescriptionIndex);

      etDescription.setTextKeepState(!TextUtils.isEmpty(taskDescription) ? taskDescription : "");
      etDate.setTextKeepState(CommonUtils.getStringDate(mCalendar, CommonUtils.getDateFormatSystem(this)));
      etTime.setTextKeepState(CommonUtils.getStringDate(mCalendar, Constant.TIME_FORMAT));
      cbIsComplete.setChecked(mCursor.getInt(mCursor.getColumnIndex(MyToDo.Tasks.COLUMN_NAME_IS_COMPLETE)) == 0 ? false
          : true);

      /*
       * Something is wrong. The Cursor should always contain data. Report an
       * error in the note.
       */
    } else {
      /*
       * setTitle("Error"); mText.setText("Error loading task");
       */
    }

    Log.d(TAG, "end:" + Calendar.getInstance().get(Calendar.MILLISECOND));
  }

  /**
   * This method is called when an Activity loses focus during its normal
   * operation, and is then later on killed. The Activity has a chance to save
   * its state so that the system can restore it. Notice that this method isn't
   * a normal part of the Activity lifecycle. It won't be called if the user
   * simply navigates away from the Activity.
   */

  @Override
  protected void onSaveInstanceState(Bundle outState) {
    // TODO Auto-generated method stub
    super.onSaveInstanceState(outState);
  }

  /**
   * This method is called when the Activity loses focus. For Activity objects
   * that edit information, onPause() may be the one place where changes are
   * saved. The Android application model is predicated on the idea that "save"
   * and "exit" aren't required actions. When users navigate away from an
   * Activity, they shouldn't have to go back to it to complete their work. The
   * act of going away should save everything and leave the Activity in a state
   * where Android can destroy it if necessary. If the user hasn't done
   * anything, then this deletes or clears out the note, otherwise it writes the
   * user's work to the provider.
   */
  @Override
  protected void onPause() {
    // Destroy the AdView.
    if (adView != null) {
      adView.pause();
    }
    super.onPause();
    Log.d(TAG, "On Pause");
  }

  @Override
  protected void onDestroy() {
    // Destroy the AdView.
    if (adView != null) {
      adView.destroy();
    }
    super.onDestroy();
  }

  private void addTask() {
    /*
     * Tests to see that the query operation didn't fail (see onCreate()). The
     * Cursor object will exist, even if no records were returned, unless the
     * query failed because of some exception or error.
     */
    if (mCursor != null) {

      // Get the current note text.
      String name = etName.getText().toString();
      String description = etDescription.getText().toString();
      String reminderDate = CommonUtils.getStringDate(mCalendar, Constant.DATE_TIME_FORMAT);
      // validate input.
      int valid = validateInput(name, description, reminderDate);
      // case: input not correct.
      if (valid != 0) {
        deleteTask();
        return;
      }

      java.util.Date reminder = CommonUtils.getDate(reminderDate, Constant.DATE_TIME_FORMAT);
      Calendar reminderCal = Calendar.getInstance();
      reminderCal.setTime(reminder);

      if (mState == STATE_EDIT) {
      } else if (mState == STATE_INSERT) {
        mState = STATE_EDIT;
      }

      updateTask(name, description, reminderDate);
      if (!isReminder && !cbIsComplete.isChecked() && reminderCal.getTimeInMillis() > System.currentTimeMillis()) {
        new ReminderManager().setReminder(this, mCursor.getLong(mCursor.getColumnIndex(MyToDo.Tasks._ID)), mCalendar,
            name, description);
      }
    }
  }

  /**
   * This method is called when the user clicks the device's Menu button the
   * first time for this Activity. Android passes in a Menu object that is
   * populated with items. Builds the menus for editing and inserting, and adds
   * in alternative actions that registered themselves to handle the MIME types
   * for this application.
   *
   * @param menu
   *          A Menu object to which items should be added.
   * @return True to display the menu.
   */
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate menu from XML resource
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.task_editor, menu);

    // Only add extra menu items for a saved task
    if (mState == STATE_EDIT) {
      Intent intent = new Intent(null, mUri);
      intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
      menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, new ComponentName(this, TaskEditorActivity.class), null,
          intent, 0, null);
    }

    return super.onCreateOptionsMenu(menu);
  }

  /**
   * This method is called when a menu item is selected. Android passes in the
   * selected item. The switch statement in this method calls the appropriate
   * method to perform the action the user chose.
   *
   * @param item
   *          The selected MenuItem
   * @return True to indicate that the item was processed, and no further work
   *         is necessary. False to proceed to further processing as indicated
   *         in the MenuItem object.
   */
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Handle all of the possible menu actions.
    switch (item.getItemId()) {
    case android.R.id.home:
      finish();
      break;
    }
    return super.onOptionsItemSelected(item);
  }

  /**
   * Validate input task. + name: required. + description: required. + date &
   * time: required.
   */
  private int validateInput(String name, String description, String dueDate) {
    // case: name null.
    if (TextUtils.isEmpty(name)) {
      return R.string.toast_err_task_name_required;
    }

    return 0;
  }

  /**
   * Update task
   * 
   * @param name
   * @param description
   * @param reminderDate
   */
  private final void updateTask(String name, String description, String reminderDate) {

    // Sets up a map to contain values to be updated in the provider.
    ContentValues values = new ContentValues();
    Account[] accounts = AccountManager.get(this).getAccountsByType(Constant.ACCOUNT_TYPE);
    if (accounts.length > 0) {
      values.put(MyToDo.Tasks.COLUMN_NAME_USER_NAME, accounts[0].name);
    }
    values.put(MyToDo.Tasks.COLUMN_NAME_UPDATE_DATE,
        CommonUtils.getStringDate(Calendar.getInstance(), Constant.DATE_TIME_FORMAT));
    values.put(MyToDo.Tasks.COLUMN_NAME_NAME, name);
    values.put(MyToDo.Tasks.COLUMN_NAME_DESCRIPTION, description);
    values.put(MyToDo.Tasks.COLUMN_NAME_REMINDER_DATE, !isReminder ? reminderDate : "");
    values.put(MyToDo.Tasks.COLUMN_NAME_IS_REMINDER, isReminder ? 0 : 1);
    values.put(MyToDo.Tasks.COLUMN_NAME_IS_COMPLETE, cbIsComplete.isChecked() ? 1 : 0);

    getContentResolver().update(mUri, values, null, null);
  }

  /**
   * Delete task
   */
  private final void deleteTask() {
    if (mCursor != null) {
      mCursor.close();
      mCursor = null;
      getContentResolver().delete(mUri, null, null);
      // TODO : Check lại
      /* mText.setText(""); */
    }
  }

  /**
   * Handle event button SelectDate click
   */
  public void selectDate(View view) {
    DialogFragment newFragment = new SelectDateFragment();
    newFragment.show(getSupportFragmentManager(), "DatePicker");
  }

  /**
   * Handle event button SelectTime click
   */
  public void selectTime(View view) {
    DialogFragment newFragment = new SelectTimeFragment();
    newFragment.show(getSupportFragmentManager(), "TimePicker");
  }

  /**
   * Open date picker
   */
  public class SelectDateFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
      int yy = mCalendar.get(Calendar.YEAR);
      int mm = mCalendar.get(Calendar.MONTH);
      int dd = mCalendar.get(Calendar.DAY_OF_MONTH);
      return new DatePickerDialog(getActivity(), this, yy, mm, dd);
    }

    @Override
    public void onDateSet(DatePicker view, int yy, int mm, int dd) {
      mCalendar.set(yy, mm, dd);
      Log.i(TAG, "Select Date : " + mCalendar.getTime().toString());

      etDate.setText(CommonUtils.getStringDate(mCalendar, CommonUtils.getDateFormatSystem(TaskEditorActivity.this)));
    }
  }

  /**
   * Open time picker
   */
  public class SelectTimeFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
      int hour = mCalendar.get(Calendar.HOUR_OF_DAY);
      int minute = mCalendar.get(Calendar.MINUTE);

      return new TimePickerDialog(getActivity(), this, hour, minute, DateFormat.is24HourFormat(getActivity()));
    }

    @Override
    public void onTimeSet(TimePicker view, int hour, int minute) {
      // TODO Auto-generated method stub

      mCalendar.set(Calendar.HOUR_OF_DAY, hour);
      mCalendar.set(Calendar.MINUTE, minute);

      Log.i(TAG, "Select Time : " + mCalendar.getTime().toString());
      etTime.setText(CommonUtils.getStringDate(mCalendar, Constant.TIME_FORMAT));
    }
  }

  /*--- EVENT SET REMINDER ON/OFF ---*/

  public void onToggleSetReminder(View view) {
    // Is the toggle on?
    isReminder = ((ToggleButton) view).isChecked();

    isShowReminder();
  }

  private void isShowReminder() {
    if (isReminder) {
      // show set date/time.
      layoutSelectTime.setVisibility(View.GONE);
      layoutSelectDate.setVisibility(View.GONE);
    } else {
      // hide set date/time.
      layoutSelectTime.setVisibility(View.VISIBLE);
      layoutSelectDate.setVisibility(View.VISIBLE);

      etDate.setTextKeepState(CommonUtils.getStringDate(mCalendar, CommonUtils.getDateFormatSystem(this)));
      etTime.setTextKeepState(CommonUtils.getStringDate(mCalendar, Constant.TIME_FORMAT));
    }
  }

  /*--- END EVENT SET REMINDER ON/OFF ---*/

  /*--Confirm dialog delete--*/
  private AlertDialog confirmDelete() {
    return CommonUtils.confirmDelete(this, new android.content.DialogInterface.OnClickListener() {

      @Override
      public void onClick(DialogInterface dialog, int which) {
        // your deleting code
        deleteTask();
        dialog.dismiss();
        finish();
      }
    }, new android.content.DialogInterface.OnClickListener() {

      @Override
      public void onClick(DialogInterface dialog, int which) {
        dialog.dismiss();
      }
    });
  }

  @Override
  public void onBackPressed() {
    addTask();
    finish();
    super.onBackPressed();
  }

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
      addTask();
      finish();
      return true;
    }

    return super.onKeyDown(keyCode, event);
  }

  private void initAdModule() {
    // Create an ad.
    adView = new AdView(this);

    adView.setAdSize(AdSize.BANNER);
    adView.setAdUnitId(Constant.ADMOD_UNIT_ID);

    // Add the AdView to the view hierarchy. The view will have no size
    // until the ad is loaded.
    LinearLayout layout = (LinearLayout) findViewById(R.id.linearEditor);
    layout.addView(adView);

    // Create an ad request. Check logcat output for the hashed device ID to
    // get test ads on a physical device.
    final AdRequest adRequest = new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
        .addTestDevice("INSERT_YOUR_HASHED_DEVICE_ID_HERE").build();

    // Start loading the ad in the background.
    adView.loadAd(adRequest);
  }
}
